#ifndef DICT_H
#define DICT_H
#include <stdlib.h>

#include "thrd.h"
//this is for thread safety...

/*
  This library is intended for small sets of values
  It is not efficient, linear searches are used.
  It's purpose is for sending data in the range of
  function argument length, so let's keep it under a hundred ok?

  Want better?  Rewrite the internals.
*/
typedef char *(*to_str_t(void *));
typedef void *(*to_dct_t(const char *));

typedef void (*free_item(void *));

struct dict_value {
  char *name;
  void *value;
  int free;
  int type;

  int hidden;

  to_str_t *to_string;
  to_dct_t *to_dict;

  struct dict_value *last;
  struct dict_value *next;
};


struct dict {
  int ref;
  struct thrd_lock *lock;
  struct dict_value *root;
  int size;
  int fast_mode; //sets assume it's a new item
#ifdef TEST
  unsigned int searches; //used in test code.
  double avg_comparisons;
#endif
  struct dict_value *last_indice;
};

#include "list.h"

#define DICT_TYPE_INT 0 
#define DICT_TYPE_STR 1
#define DICT_TYPE_DCT 2 // a nested dictionary
#define DICT_TYPE_OBJ 3
#define DICT_TYPE_LST 4

struct dict *dict_new();
//Pre: size is the max number of items it can hold
//Post: makes this structure

//don't use the following, unless you're sure!:
void dict_free(struct dict *d);
//Pre:  
//Post: Free's d, and all its children! 

void dict_ref(struct dict *d);
//Pre: d is new'ed
//Post:  references d's ref count

void dict_unref(struct dict *d);
//Pre:
//Post:  dereferences d, free's if logical

void dict_print(struct dict *d);
//Pre:
//Post:  Prints d to the screen, recursively.

void dict_remove(struct dict *d, const char *name);
//Pre:
//Post:  item name is removed from dict d.

void dict_set(struct dict *d, const char *name, void *value);
//Pre:
//Post:  name is associated with value inside the dict.
//       name will be copied, value will not.

void dict_go_fast(struct dict *d);
//turns on fast modes, here dict_set assumes it's a new value
//each time.

void dict_go_right(struct dict *d);
//returns to default mode, dict_set searches first.


int dict_check(struct dict *d, ...);
//Pre: ... is a NULL terminated list of key's
//Post:  Returns 1 if a key doesn't exist, 0 if all exist

int dict_rcheck(struct dict *d, ...);
//Pre: ... is a NULL terminated list of keys
//Post:  Returns 1 if a key doesn't exist, 0 if all exist
//Each key moves into the last as if it were a dictionary.

void *dict_rget(struct dict *d, ...);
//Pre: null terminated list of recursive names
//Post:  returns that item
//NOTE:  This is a recursive form of dict_get.

void *dict_get(struct dict *d, const char *name);
//Pre:
//Post:  finds the name..

struct list *dict_get_list(struct dict *d, const char *name);
//Pre:  
//Post:  If d[name] is a DCT_TYPE_DCT it forms a list from it and returns it
//		if d[name] is a DCT_TYPE_LST it returns it
//		otherwise you get NULL;

void dict_set_free(struct dict *d, const char *name, int stat);
//Pre: stat=0 means don't ever free it, stat=1 means ok to free it
//Post:  your word is law.

void dict_set_type(struct dict *d, const char *name, int type);
//Pre: type is one of the defined types near the top:  DICT_TYPE_STR default
//Post:  type is set

int dict_get_type(struct dict *d, const char *name);
//Pre:  the usual
//Post:  Returns the type enumeration for value name in dict d.
//Returns -1 on error.


void dict_set_hidden(struct dict *d, const char *name, int h);
//Pre:
//Post:  if h is 1, this value won't be printed in any way.
//It will have to be accessed only with dict_get(d, name)

void dict_set_free_functor(struct dict *d, const char *name, free_item);

void dict_set_convert(struct dict *d, const char *name, 
					  to_str_t to_string, to_dct_t to_dict);
//Pre: to_string and to_dict may be NULL.
//Post:  Will remember to use these functions to convert to and from text
//       if needed.


//python functions are not yet thread safe...
#ifdef PYTHON
#include <python2.4/Python.h>
PyObject *dict_to_py(struct dict *d);
// translates d to a python dict
//only use this if all items on dict are strings!

void py_to_dict(struct dict *d, PyObject *p);
//Moves changes back in...

#endif
#endif 
